# -*- coding: utf-8 -*-
#python built-in
import pickle
#wxpython
import wx
import wx.lib.newevent
import wx.grid
#bbswatcher
import adapter.smth
import driver
import model
import regist
import gui.dialogs

NotifyMatchEvent, EVT_NOTIFY_MATCH = wx.lib.newevent.NewEvent()

ui = None

def notifyMatch(msg, matchresult):
    #create the event
    evt = NotifyMatchEvent(msg = msg, result = matchresult)
    #post the event
    wx.PostEvent(ui, evt)
    
class BBSWatcherApp(wx.App):
    def __init__(self):
        wx.App.__init__(self, True)
        
    def OnInit(self):
        frame = BBSWatcherFrame()
        frame.Show()
        return True

class BBSWatcherFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, u"BBS Watcher beta 0.8.0.1", size=(700,600), pos= (200,200), style = wx.CAPTION|wx.NO_BORDER|wx.SYSTEM_MENU|wx.CLOSE_BOX|wx.MINIMIZE_BOX)
        self.watcherThreads = {}
        self.configs = []
        self.icon = wx.Icon('resources/tray.ico', wx.BITMAP_TYPE_ICO)
        self.buttons = {}
        self.CreateControls(self)
        self.CreateStatusBar()
        self.CreateTaskBarIcon()
        self.timer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.Prepare, self.timer)
        self.timer.Start(milliseconds=500, oneShot=True)
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnClose)
        self.SetIcon(self.icon)
        driver.setUIMode(True)
        global ui
        ui = self
        self.Bind(EVT_NOTIFY_MATCH, self.TrayNotify)
        self.Bind(wx.EVT_ICONIZE, self.OnIconize)
        self.tip = None
    
    def oniconize(self,event):
        print 'hello'
        
    def CreateControls(self, parent):
        panel = wx.Panel(parent, -1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.CreateLabel(panel,u'配置文件列表:'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP |wx.BOTTOM , 10)
        sizer.Add(self.CreateConfigArea(panel),0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM , 10)
        sizer.Add(self.CreateResultArea(panel),1, wx.EXPAND |wx.LEFT|wx.RIGHT|wx.BOTTOM, 5)
        panel.SetSizer(sizer)
        sizer.Layout()
        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(panel, 1, wx.EXPAND, 0)
        parent.SetSizer(mainsizer)
        mainsizer.Layout()
        
    def CreateConfigArea(self, parent):
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.CreateConfigList(parent),1, wx.EXPAND|wx.RIGHT, 5)
        sizer.Add(self.CreateButtonBar(parent), 0, wx.ALIGN_RIGHT, 5)
        return sizer
        
    def CreateButtonBar(self, parent):
        sizer = wx.BoxSizer(wx.VERTICAL)
        labels = (u'添加',u'编辑',u'删除',u'开始',u'停止',u'全部开始',u'全部停止')
        names = ('add','edit','delete','start','stop','startall','stopall')
        handlers = (self.OnAdd,self.OnEdit,self.OnDelete,self.OnStart,self.OnStop,self.OnStartAll,self.OnStopAll)
        for i, info in enumerate(zip(names,labels,handlers)):
            self.buttons[info[0]] = self.CreateButton(parent, info[1], info[2])
            sizer.Add(self.buttons[info[0]], 0, wx.CENTER| wx.LEFT| wx.BOTTOM, 5)
        return sizer
    
    def CreateButton(self, parent, name, handler):
        button = wx.Button(parent, -1,name)
        self.Bind(wx.EVT_BUTTON, handler, button)
        button.Disable()
        return button
            
    def CreateConfigList(self, parent):
        self.configList = ConfigListCtrl(parent,[])
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, lambda event:self.UpdateControls(False), self.configList)
        return self.configList
        
    def CreateLabel(self, parent, label):
        return wx.StaticText(parent, -1, label)
        
    def CreateTaskBarIcon(self):
        self.trayIcon = wx.TaskBarIcon()
        self.trayIcon.SetIcon(self.icon)
        wx.EVT_TASKBAR_LEFT_DCLICK(self.trayIcon,self.OnTaskBarLeftDClick)

    def CreateResultArea(self, parent):
        sizer = wx.BoxSizer(wx.VERTICAL)
        subsizer = wx.BoxSizer(wx.HORIZONTAL)
        subsizer.Add(self.CreateLabel(parent,u'匹配结果:'), 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP |wx.BOTTOM , 5)
        subsizer.Add(self.CreateResultButtonBar(parent),0,wx.ALL, 5)
        subsizer.Add(self.CreateResultFilter(parent), 0, wx.LEFT | wx.RIGHT | wx.TOP |wx.BOTTOM |wx.ALIGN_RIGHT, 5)
        sizer.Add(subsizer,0, wx.EXPAND, 5)
        subsizer = wx.BoxSizer(wx.HORIZONTAL)
        tb = self.CreateResultList(parent)
        subsizer.Add(tb, 0, wx.ALIGN_LEFT|wx.EXPAND, 0)
        rdarea = self.CreateResultDetailArea(parent)
        subsizer.Add(rdarea, 1, wx.EXPAND|wx.CENTER,0)
        sizer.Add(subsizer,1, wx.EXPAND|wx.ALL, 5)
        return sizer
    
    def CreateResultFilter(self, parent):
        self.resultFilter = wx.Choice(parent, -1, size = (200,-1),choices=[])
        self.Bind(wx.EVT_CHOICE, self.resetResultFilter, self.resultFilter)
        return self.resultFilter
    
    def CreateResultButtonBar(self, parent):
        panel = wx.Panel(parent, -1)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.clearResultButton = wx.Button(panel, -1,u'清除结果')
        self.Bind(wx.EVT_BUTTON,self.OnClearResult,self.clearResultButton)
        sizer.Add(self.clearResultButton, 0, wx.ALL, 0)
        panel.SetSizer(sizer)
        sizer.Layout()
        return panel
        
    def CreateResultList(self, parent):
        self.resultList = ResultListCtrl(parent, [])
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, lambda event: self.updateresultdetailcontent(), self.resultList)
        return self.resultList
    
    def CreateResultDetailArea(self, parent):
        panel = wx.Panel(parent, -1,style= wx.BORDER)
        panel.SetBackgroundColour(wx.WHITE)
        sizer = wx.BoxSizer(wx.VERTICAL)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.postTitleLabel = self.createcontentlabel(panel,  '')
        self.postTimeLabel = self.createcontentlabel(panel,  '')
        self.postUserLabel = self.createcontentlabel(panel,  '')
        self.postContentBox = self.createcontentlabel(panel,  '')
        self.postLink = self.createlink(panel, '#')
        self.postContentBox = self.createcontenttextarea(panel, '')
        
        hsizer.Add(self.createkeylabel(panel, u'帖子标题：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postTitleLabel, 1, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND|wx.ALL, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.createkeylabel(panel, u'发帖时间：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postTimeLabel, 1, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND|wx.ALL, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.createkeylabel(panel, u'发帖用户：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postUserLabel, 1, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND|wx.ALL, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.createkeylabel(panel, u'帖子链接：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postLink, 0, wx.ALIGN_LEFT |wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        self.postLink.Hide()
        sizer.Add(hsizer,0,wx.EXPAND|wx.ALL, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.createkeylabel(panel, u'帖子内容：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postContentBox, 1, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,1,wx.EXPAND|wx.ALL, 5)
        panel.SetSizer(sizer)
        panel.Layout()
        return panel
    
    def createkeylabel(self, parent, label):
        lbl = wx.StaticText(parent, -1, label)
        font = wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False)
        lbl.SetFont(font)
        lbl.SetForegroundColour(wx.Color(70,50,120))
        return lbl
    
    def createcontentlabel(self, parent, label):
        lbl = wx.StaticText(parent, -1, label)
        font = wx.Font(9, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
        lbl.SetFont(font)
        lbl.SetForegroundColour(wx.Color(80,80,80))
        return lbl
    
    def createcontenttextarea(self, parent, label):
        tc = wx.TextCtrl(parent, -1, style=wx.TE_MULTILINE|wx.NO_BORDER)
        tc.SetEditable(False)
        font = wx.Font(9, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
        tc.SetFont(font)
        return tc
    
    def createlink(self, parent, link):
        lnk = wx.HyperlinkCtrl(parent, -1, link, link)
        lnk.SetNormalColour(wx.Color(100,100,250))
        lnk.SetHoverColour(wx.Color(50,50,200))
        lnk.SetVisitedColour(wx.Color(100,100,250))
        return lnk
    
    def updateresultdetailcontent(self):
        index = self.resultList.GetFirstSelected()
        result = None
        if index>=0:
            result = self.resultList.GetResult(index)
        if not result:
            self.postTitleLabel.SetLabel('')
            self.postTimeLabel.SetLabel('')
            self.postUserLabel.SetLabel('')
            self.postContentBox.Clear()
            self.postLink.Hide()
        else:
            self.postTitleLabel.SetLabel(result.post.getTitle())
            self.postTimeLabel.SetLabel(time.asctime(result.post.getTime()))
            self.postUserLabel.SetLabel(result.post.getUser())
            self.postLink.SetLabel(result.post.getLink())
            self.postLink.SetURL(result.post.getLink())
            self.postLink.Show()
            self.postContentBox.Clear()
            if result.post.getContent():
                self.postContentBox.WriteText(result.post.getContent())
                self.postContentBox.SetSelection(0,0)
            self.postLink.Parent.Layout()

    # event handlers

    def resetResultFilter(self,event):
        index = self.resultFilter.GetSelection() - 1
        if index <0:
            self.resultList.SetResultFilter(None)
        else:
            config = self.configs[index]
            self.resultList.SetResultFilter(config)
            
    def OnAdd(self, event):
        dlg = gui.dialogs.WatchConfigDialog(self, -1, u'新建配置')
        if wx.ID_OK == dlg.ShowModal():
            config = dlg.GetWatchConfig()
            if config:
                self.configs.append(config)
                self.UpdateControls(True)
        dlg.Destroy()
                
    def OnIconize(self, event):
        if self.IsIconized():
            self.Hide()

    def OnEdit(self, event):
        i = self.configList.GetFirstSelected()
        if i < 0:
            return 
        config = self.configs[i]
        if not config or not config.stopped:
            return
        dlg = gui.dialogs.WatchConfigDialog(self, -1, u'新建配置', cfg = config)
        if wx.ID_OK == dlg.ShowModal():
            editedconfig = dlg.GetWatchConfig()
            if editedconfig:
                self.configs[i] = editedconfig
                self.UpdateControls(True)
        dlg.Destroy()
        
    def OnDelete(self, event):
        i = self.configList.GetFirstSelected()
        if i <0:
            return 
        config = self.configs[i]
        if not config or not config.stopped:
            return
        self.configs.remove(config)
        self.UpdateControls(True)
      
    def OnStart(self, event):
        i = self.configList.GetFirstSelected()
        if i <0:
            return 
        config = self.configs[i]
        self.StartConfig(config)
        self.UpdateControls(False)
        
    def OnStop(self, event):
        i = self.configList.GetFirstSelected()
        if i <0:
            return 
        config = self.configs[i]
        self.StopConfig(config)
        self.UpdateControls(False)
      
    def OnStartAll(self, event):
        for config in self.configs:
            self.StartConfig(config)
        self.UpdateControls(False)
    
    def OnStopAll(self, event):
        self.tip.Destroy()
        for config in self.configs:
            self.StopConfig(config)
        self.UpdateControls(False)

    def OnClose(self, event):
        self.trayIcon.Destroy()
        if self.tip:
            self.tip.Destroy()
        for config in self.configs:
            self.StopConfig(config)
        self.save()
    
    def OnTaskBarLeftDClick(self, event):
        if self.IsIconized():
            self.Iconize(False)
            self.Show()
        else:
            self.Iconize(True)
            self.Hide()
        self.Raise()

    def OnClearResult(self,event):
        self.resultList.SetResults([])
        
    #other methods
    def TrayNotify(self, event):
        if not self.tip:
            import gui.BalloonTip as BT
            self.tip = BT.BalloonTip(topicon=None,
                                toptitle=u'发现符合要求的帖子',
                                message=event.msg,
                                shape=BT.BT_ROUNDED,
                                tipstyle=BT.BT_BUTTON,
                                showmode=BT.BT_SHOW_MANUALLY,
                                frameclass = PostNotificationBalloonFrame,
                                customdata = event.result.post)
            # Set The Target
            font1 = wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False)
            self.tip.SetTarget(self.trayIcon)
            self.tip.SetBalloonColour(wx.Color(0,0,0))
            self.tip.SetTitleFont(font1)
            self.tip.SetTitleColour(wx.Color(150,150,250))
            self.tip.SetMessageColour(wx.Color(250,250,250))
            self.tip.SetStartDelay(500)
            self.tip.SetEndDelay(5000)
        self.tip.SetBalloonMessage(event.msg)
        self.tip.SetCustomData(event.result.post)
        self.tip.Show()
        self.resultList.AddResult(event.result)
        
    def StopConfig(self, config):
        if not config or config.stopped:
            return
        thread = self.watcherThreads.get(config.name)
        if not thread or thread.stopped:
            config.stopped = True
            return
        thread.stop()
        thread.join()
        self.watcherThreads.pop(config.name,None)
        config.stopped = True
    
    def StartConfig(self, config):
        if not config or not config.stopped:
            return
        thread = self.watcherThreads.get(config.name)
        if thread and not thread.stopped:
            thread.stop()
        thread = driver.BBSWatcher(config, 10, notifyMatch )
        self.watcherThreads[config.name] = thread
        config.stopped = False
        thread.start()
        
    def Prepare(self, event):
#        if not regist.validate():
#            if not self.Register():
#                self.Destroy()
        self.LoadConfig()
        self.timer.Stop()
        del self.timer
  
    def UpdateControls(self, itemschanged):
        #update list
        if itemschanged:
            i = self.configList.GetFirstSelected()
            items = [c for c in self.configs]
            self.configList.SetConfigs(items)
            #
            i = self.resultFilter.GetSelection()
            items = [u'显示所有结果']
            items.extend([c.name for c in self.configs])
            self.resultFilter.SetItems(items)
            if i > len(self.resultFilter.GetItems()):
                i = len(self.resultFilter.GetItems())
            if i<0:
                i = 0
            self.resultFilter.SetSelection(i)
        self.configList.UpdateItems()
        #update buttons
        self.UpdateButtonStatus()
        
    def UpdateButtonStatus(self):
        i = self.configList.GetFirstSelected()
        self.buttons['add'].Enable()
        if i <0:
            for name in ('edit','delete','start','stop'):
                self.buttons[name].Disable()
        else:
            for name in ('edit','delete','start','stop'):
                self.buttons[name].Enable()
            config = self.configs[i]
            if not config.stopped:
                for name in ('edit','delete','start'):
                    self.buttons[name].Disable()
            else:
                self.buttons['stop'].Disable() 
        
        if not self.configList.GetItemCount():
            for name in ('startall','stopall'):
                self.buttons[name].Disable()
        else:
            for name in ('startall','stopall'):
                self.buttons[name].Enable()
        
    def LoadConfig(self):
        self.load()
        self.UpdateControls(True)
    
    def load(self):
        try:
            file = open(r'resources/cfg.dat','r')
            cfgs = pickle.load(file)
            self.configs = cfgs
        except:
            return
        
    def save(self):
        try:
            file = open(r'resources/cfg.dat','w')
            pickle.dump(self.configs, file)
        except:
            return
    
    def SetStatus(self, msg):
        self.StatusBar.SetStatusText(msg)

    def Register(self): 
        if wx.MessageBox( u'您还没有注册，想现在注册吗？',u'您还没有注册',wx.YES|wx.NO) == wx.YES:
            while True:
                promote = u"您需要将机器码放送至管理员处，以便获得您的注册码\n您的机器码为 %s " %(regist.machinecode(),)
                dialog = wx.TextEntryDialog(self, promote, caption = "输入如注册码")
                code = None
                if dialog.ShowModal() == wx.ID_OK:
                    code = dialog.GetValue().strip()
                    if(regist.checkcode(code)):
                        wx.MessageBox( u'恭喜您，注册成功！',u'注册成功',wx.OK)
                        return True
                    else:
                        wx.MessageBox( u'对不起，您输入的注册码不正确，请重新输入！',u'注册失败',wx.OK)
                else:
                    dialog.Destroy()
                    return False
                dialog.Destroy()
        else:
            return False
        return False

import gui.BalloonTip as BT
import time
class PostNotificationBalloonFrame(BT.BalloonFrame):
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, classparent=None):
        BT.BalloonFrame.__init__(self, parent, id, pos, size, classparent)
        
    def __createContentPane__(self, parent):
        post = self._customdata
        if not isinstance(post, model.Post):
            return BT.BalloonFrame.__createContentPane__(self, parent)
        panel = wx.Panel(parent, -1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.postTitle = self.__createLabel__(panel,  post.getTitle())
        self.postTime = self.__createLabel__(panel, time.asctime(post.getTime()))
        self.postUser = self.__createLabel__(panel,post.getUser())
        self.postLink = self.__createLink__(panel,post.getLink(), post.getLink())
        self.postContent = self.__createContentTextArea__(panel)
        hsizer.Add(self.__createLabel__(panel, u'帖子标题：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postTitle, 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.__createLabel__(panel, u'发帖时间：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postTime, 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.__createLabel__(panel, u'发帖用户：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postUser, 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.__createLabel__(panel, u'帖子链接：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postLink, 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND, 5)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.__createLabel__(panel, u'帖子内容：'), 0, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        hsizer.Add(self.postContent, 1, wx.EXPAND | wx.LEFT | wx.RIGHT
                         | wx.BOTTOM | wx.TOP, 5)
        sizer.Add(hsizer,0,wx.EXPAND, 5)
        panel.SetSizer(sizer)
        panel.Layout()
        return panel
    
    def __updateContent__(self):
        BT.BalloonFrame.__updateContent__(self)
        post = self._customdata
        if not isinstance(post, model.Post):
            return
        self.postTitle.SetLabel(post.getTitle())
        self.postUser.SetLabel(post.getUser())
        self.postTime.SetLabel(time.asctime(post.getTime()))
        self.postLink.SetLabel(post.getLink())
        self.postLink.SetURL(post.getLink())
        self.postContent.Clear()
        if post.getContent():
            self.postContent.WriteText(post.getContent())
            self.postContent.SetSelection(0,0)
        self.Refresh()
    
    def __createLabel__(self, parent, label):
        label = wx.StaticText(parent, -1, label)
        label.SetForegroundColour(wx.WHITE)
        return label
    
    def __createLink__(self, parent, label, link):
        lnk = wx.HyperlinkCtrl(parent, -1, label, link)
        lnk.SetNormalColour(wx.Color(150,150,250))
        lnk.SetHoverColour(wx.Color(100,100,200))
        lnk.SetVisitedColour(wx.Color(150,150,250))
        return lnk
    
    def __createContentTextArea__(self, parent, label=""):
        tc = wx.TextCtrl(parent, -1, style=wx.TE_MULTILINE|wx.NO_BORDER, size=(100,100))
        tc.SetEditable(False)
        font = wx.Font(9, wx.SWISS, wx.NORMAL, wx.NORMAL, False)
        tc.SetFont(font)
        tc.SetForegroundColour(wx.WHITE)
        tc.SetBackgroundColour(wx.BLACK)
        return tc

class ConfigListCtrl(wx.ListCtrl):
    def __init__(self, parent, configs):
        wx.ListCtrl.__init__(self, parent,
            style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL)
        self.configs = configs
        self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)
        self.SetItemCount(len(self.configs))

        for col, text in enumerate((u'配置名称',u'状态')):
            self.InsertColumn(col, text)
        self.SetColumnWidth(0, 300)
        self.SetColumnWidth(1, 260)
        self.UpdateItems()
        
    def DoCacheItems(self, evt):
        #self.dataSource.UpdateCache(
        #    evt.GetCacheFrom(), evt.GetCacheTo())
        pass

    def OnGetItemText(self, item, col):
        config = self.configs[item]
        if col == 0:
            return config.name
        elif col == 1:
            if config.stopped:
                return u'已停止'
            else:
                return u'正在运行'
        return ''

    def OnGetItemAttr(self, item):
        return None
    def OnGetItemImage(self, item):
        return -1

    def SetConfigs(self,configs ):
        self.configs = configs
        self.UpdateItems()
        
    def UpdateItems(self):
        self.SetItemCount(len(self.configs))
        self.Refresh()

class ResultListCtrl(wx.ListCtrl):
    def __init__(self, parent, results):
        wx.ListCtrl.__init__(self, parent,size=(250,300),
            style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL)
        self.resultsToDisplay = []
        self.results = []
        self.results.extend(results)
        self.resultFilter = None
        self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)

        for col, text in enumerate((u'所属配置',u'帖子标题')):
            self.InsertColumn(col, text)
        self.SetColumnWidth(0, 80)
        self.SetColumnWidth(1, 300)
        self.UpdateItems()
        
    def DoCacheItems(self, evt):
        pass

    def OnGetItemText(self, item, col):
        if col == 0:
            return self.resultsToDisplay[item].config.name
        elif col == 1:
            return self.resultsToDisplay[item].post.getTitle()
        return ''

    def OnGetItemAttr(self, item):
        return None
    def OnGetItemImage(self, item):
        return -1

    def SetResults(self,results ):
        while len(self.results):
            self.results.pop()
        self.results.extend(results)
        self.UpdateItems()
        
    def AddResult(self, result):
        self.results.append(result)
        self.UpdateItems()
        
    def GetResult(self, index):
        if index >= len(self.resultsToDisplay) or index <0:
            return None
        return self.resultsToDisplay[index]
    
    def UpdateItems(self):
        while len(self.resultsToDisplay):
            self.resultsToDisplay.pop()
        if not self.resultFilter:
            self.resultsToDisplay.extend(self.results)
        else:
            self.resultsToDisplay.extend([r for r in self.results if self.resultFilter == r.config])
        self.SetItemCount(len(self.resultsToDisplay))
        self.Refresh()
        
    def SetResultFilter(self, config):
        self.resultFilter = config
        self.UpdateItems()
 
if __name__ == '__main__':
    app = BBSWatcherApp()
    app.MainLoop()